package net.tngou.crawler.action;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;



import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import javax.servlet.http.HttpServletResponse;




import org.apache.commons.configuration2.builder.FileBasedBuilderParametersImpl;

import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.io.FileHandler;
import org.apache.commons.configuration2.io.FileLocatorUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import net.tngou.crawler.http.HttpRequest;
import net.tngou.crawler.http.HttpResponse;
import net.tngou.crawler.http.HttpSession;
import net.tngou.crawler.http.SessionContext;
import net.tngou.crawler.jdbc.Ask;
import net.tngou.crawler.jdbc.DBManager;
import net.tngou.crawler.jdbc.PageUtil;
import net.tngou.crawler.pojo.POJO;
import net.tngou.crawler.service.BaseService;
import net.tngou.crawler.util.BeanUtil;
import net.tngou.crawler.util.ConfigurationUtil;


/**
 * 所有的action类的父类
 * @author 陈磊
 *
 */
public  abstract class BaseAction  
{

	private static final Logger log= LoggerFactory.getLogger(BaseAction.class);
	@SuppressWarnings("rawtypes")
	private static Class[] NO_ARGS_CLASS = new Class[0];
	private static Object[] NO_ARGS_OBJECT = new Object[0];
	protected HttpRequest request;
	protected HttpResponse response;
	protected ServletContext context;
	protected HttpSession session;
	protected Configuration cfg; 
	protected Map<String, Object> root = new HashMap<String, Object>();
	protected static final String Prefix=POJO.DABASE+"_";
	protected BaseService service = new BaseService();
	protected final static int SIZE=20;
	protected Ask ask;
	protected Map<String,String> info;
	/**
	 * 初始化
	 * @param request
	 * @param response
	 * @throws ConfigurationException 
	 */
	public void init(HttpRequest request, HttpResponse response)  {
		this.request = request;
		this.response = response;
		this.context = request.getServletContext(); //3.0
		this.session = new SessionContext();
		this.info=getInfo();
		this.ask=getAsk(Ask.class);
		String[] params = request.getParams();
		if(params!=null&&params.length>0&&NumberUtils.isNumber(params[0])&&ask.getId()==0) {
			ask.setId(Integer.parseInt(params[0]));
		}
		cfg = new Configuration(Configuration.getVersion());
		 
		try {
		
		    //加载并设置freemarker.properties  
			FileBasedBuilderParametersImpl builder =
				    new FileBasedBuilderParametersImpl()
				        .setFileName("freemarker.properties");
	      FileHandler header = builder.getFileHandler();
	      InputStream inputStream = new FileInputStream(FileLocatorUtils.fileFromURL(header.getURL()));
		  cfg.setSettings(inputStream);
		   
			
		     
			
		} catch (  IOException | TemplateException e) {
			log.error("读取配置文件freemarker.properties错误！");
			e.printStackTrace();
		}
	
		cfg.setServletContextForTemplateLoading(
				context, "WEB-INF/templates");
		cfg.setDefaultEncoding("UTF-8");
		
		
	}
	
	/**
	 * 执行的类
	 * @throws ServletException
	 * @throws IOException
	 */
	public  void run() 
	{
			String action = request.getAction();
		
			//aop调用 执行 action 方法
					try {
						this.getClass().getMethod(action, NO_ARGS_CLASS).invoke(this, NO_ARGS_OBJECT);
					} catch (Exception e) {
						log.error("{} 类中 没有实现 {}方法 \n" + e,this.getClass(),action);
						run_404();//返回500
						e.printStackTrace();
					}finally
					{
						DBManager.closeConnection();//关闭数据库连接
					}
				

	};
	
	public  void run(String action) 
	{
			//String action = request.getAction();
		
			//aop调用 执行 action 方法
					try {
						this.getClass().getMethod(action, NO_ARGS_CLASS).invoke(this, NO_ARGS_OBJECT);
					} catch (Exception e) {
						log.error("{} 类中 没有实现 {}方法 \n" + e,this.getClass(),action);
						run_404();//返回500
						e.printStackTrace();
					}finally
					{
						DBManager.closeConnection();//关闭数据库连接
					}
				

	};
	
	protected void destroy()
	{
		
	}
	
	/**
	 * 默认执行的方法
	 * @throws ServletException
	 * @throws IOException
	 */
	public void execute() throws ServletException, IOException 
	{
		log.error("{} 类中 没有继承 execute() 方法 \n" ,this.getClass());
		

	}
	
	/**
	 * 跳转后浏览器地址栏变化<br>
	 * <p>
	 * 传值出去的话，只能在url中带parameter或者放在session中，无法使用request.setAttribute来传递。<br> 
	 * @param url 重定向访问的路径  http://127.0.0.1:8080/ape/index.html
	 */
	protected void sendRedirect(String url)
	{
		try {
		
			response.sendRedirect(url);	
		} catch (IOException e) {
			log.error("访问的URL{}不存在！\n"+e,url);
			run_404();
			e.printStackTrace();
		}
		return;
	}
	
	/**
	 * 301、302  都表示重定向， 区别是 301 是永久性重定向，302 是临时性重定向。
	 * 301
		SC_MOVED_PERMANENTLY
		页面已经永久移到另外一个新地址
		302
		SC_MOVED_TEMPORARILY
		页面暂时移动到另外一个新的地址
	 * @param url
	 * @param status
	 */
	protected void sendRedirect(String url,int status)
	{

			response.addHeader("location", url);
			response.setStatus(status);
							
		return;
	}
	
	/**
	 * Servlet页面跳转的路径是相对路径。forward方式只能跳转到本web应用中的页面上。
	 *<br>
	 *	跳转后浏览器地址栏不会变化。
	 *<br>
	 *使用这种方式跳转，传值可以使用三种方法：url中带parameter，session，request.setAttribute
	 *
	 * @param uri 跳转的相对路径 如：input.jsp
	 */
	public void forward(String uri) {
		
		
			try {
				request.getRequestDispatcher(uri).forward(request, response);
			} catch (ServletException | IOException e) {
				run_500();//返回500
				e.printStackTrace();
			} 
			
		
		return;
	}
	
	
	/**
	 * text/html 格式的返回
	 * @param html 显示的html
	 */
	protected void printHtml(String html) 
	{
		try {
			response.setContentType("text/html; charset=UTF-8");
			response.getWriter().print(html);
		} catch (IOException e) {
			log.error("显示text/html{}报错\n"+e,html);
			run_500();//返回500
			e.printStackTrace();
			
		}
		return;
	}
	
	/**
	 * application/json 格式的返回json
	 * @param json 返回的json
	 */
	/**
	 * application/json 格式的返回json
	 * @param json 返回的json
	 */
	protected void printJson(String json) {
		try {
			response.setContentType("application/json; charset=UTF-8");
	        response.setDateHeader("Expires", System.currentTimeMillis()+3600*1000*1);//缓存一小时
	        response.setHeader("Cache-Control", "public,max-age="+3600*1000*1);
            response.setHeader("Pragma", "Pragma");
	        response.getWriter().print(json);
		} catch (IOException e) {
			log.error("返回application/json{}报错\n"+e,json);
			run_false();//返回500
			e.printStackTrace();
		}
		return;
	}
	
	/**
	 *    通过Freemarker方式显示
	 * @param ftl ftl文件
	 * @param root 数据
	 */
 protected void printFreemarker(String ftl,Map<String,Object> root)
  {
	 
	//HttpSession session = new SessionContext( request);


	 //设置默认信息
	 if(root.get("title")==null)  root.put("title", info.get("title"));
	 if(root.get("keywords")==null)  root.put("keywords", "");
	 if(root.get("description")==null)  root.put("description", "");
	 if(root.get("author")==null)  root.put("author", "tngou.net");
	 if(root.get("action")==null)  root.put("action", request.getAction());
	 if(root.get("module")==null)  root.put("module", request.getModule());
	 root.put("info", info);
	 try {
		Template  t = cfg.getTemplate(ftl);
		t.setEncoding("UTF-8");
		response.setContentType("text/html; charset=" + t.getEncoding());
		Writer out = response.getWriter();
		t.process(root, out);
	
	} catch (IOException | TemplateException  e) {
		log.error("通过Freemarker文件{}错误",ftl);
		run_500();//返回500
		e.printStackTrace();

	}
      
  }
 
 

 
 /**
  * 500页面
  */
	 public void run_500() {
		 try {
			response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
			response.setCharacterEncoding("UTF-8");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}//返回500
	}
 
	 /**
	  * 404页面
	  */
	 public void run_404() {
		 try {
			response.sendError(HttpServletResponse.SC_NOT_FOUND);
			response.setCharacterEncoding("UTF-8");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	 
	 /**
	  * 403页面
	  */
	 public void run_403() {
			
		 try {
			response.sendError(HttpServletResponse.SC_FORBIDDEN );
			response.setCharacterEncoding("UTF-8");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	 }
	  
	 protected <T> T getAsk( Class<T> beanClass)
		{
			Map<String, ? extends Object> map = request.getParameterMap();
						
			T t = null;
			try {
				t = beanClass.newInstance();
				BeanUtil.populate(t, map);
			} catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}		
			return t;
		}
	 
	 
	
	 
	
	 

	 

	 /**
	  * 404页面
	  */
	 public void run_false() {
		
		 String json="{\"status\": false}";
		String callback = this.ask.getCallback();
		printJson(this.toJsonP(callback , json));
	}
	 
	 public void run_false(String message) {
		
		 JSONObject jsonObject = new JSONObject();
		 jsonObject.put("status", false);
		 jsonObject.put("msg", message);		
		printJson(this.toJsonP(jsonObject));
	}
	 
	 public void run_nologin() {
			
		 String json="{\"status\": false,\"msg\": \"access_token参数失效，需要用户认证\"}";
	
		printJson(this.toJsonP(ask.getCallback(), json));
	}
	
	 public void run_success(String message) {
			JSONObject obj = new JSONObject();
			obj.put("status", true);
			obj.put("msg", message);
			printJson(this.toJsonP(this.ask.getCallback(), obj.toString()));
	}
	
	 /**
		 * 这里返回的数据主要有JSonp了Json两种处理方式
		 */
		private String toJsonP(String callback,String json)
		{
			if(callback!=null)
			{
				json=callback+"("+json+")";
			}
			return json;
		}
		public String toJsonP(Object pojo)
		{
			JSONObject jsonObject = (JSONObject) JSONObject.toJSON(pojo);
			jsonObject.put("status", true);	
			return toJsonP(ask.getCallback(), jsonObject.toJSONString());
		}
		public String toJsonP(List<?> list)
		{
			JSONArray array = (JSONArray) JSONObject.toJSON(list);
			return toJsonP(array);
		}
		public String toJsonP( JSONObject jsonObject)
		{
			if(jsonObject.get("status")==null)jsonObject.put("status", true);	
			return toJsonP(ask.getCallback(), jsonObject.toJSONString());
		}
		public String toJsonP(JSONArray array) {
			JSONObject jsonObject = new JSONObject();
			jsonObject.put("list", array);
			return toJsonP(jsonObject);
		}
		private String toJsonP(String callback,String json,int total)
		{
			if(callback==null)
			{
				json="{ \"status\":"+true+",\"total\":"+total+",\"list\":"+json+"}";
			}else
			{
				json=callback+"({ \"status\":"+true+",\"total\":"+total+", \"list\":"+json+"})";
			}
			return json;
		}
		public String toJsonP(String json,int total)
		{			
			return toJsonP(ask.getCallback(), json, total);
		}
	
		/**
		 *  把Page转为JSON 数据
		 * @param page
		 * @return
		 */
		public String toJsonPage(PageUtil page) {
			String callback =ask.getCallback();
		
			List<?> list =  page.getList();	 	
			 String json=JSON.toJSONString(list);
			return toJsonP(callback, json, page.getTotal());

				
		}

		
	
		/**
		 * 判断参数是否为空！
		 * 
		 * @param args
		 * @return
		 */
		protected boolean isEmpty(Object... args) {

			for (Object string : args) {
				if (string == null)
					return true;
				if (StringUtils.isEmpty(string.toString()))
					return true;
			}
			return false;

		}
		 public Map<String, String> getInfo() {
				org.apache.commons.configuration2.Configuration conf = ConfigurationUtil.config("info.properties");
				Map<String, String> cp_props =new HashMap<String, String>();//使用cp_props做临时的配置文件的存储
				Iterator<String> iterable = conf.getKeys();//取得配置文件中的key
				while (iterable.hasNext()) {
					String skey=iterable.next();
					  cp_props.put(skey,conf.getString(skey));				
				}
				String url = cp_props.get("domain");
				if(url.startsWith("http"))
					url=StringUtils.remove(url, "http://");	
				if(url.startsWith("https"))
					url=StringUtils.remove(url, "https://");	
				url=request.getScheme()+"://"+url;
				if(!url.startsWith("http"))url="//"+url;
				cp_props.put("domain", url);
				return cp_props;
				
			}
	
}
